﻿using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using WH.Contracts.Systems.Users;
using WH.Model.Enums;
using WH.Model.Systems;
using WH.Services.IServices.ISystem;
using Rw.Core.Common;
using Rw.Core.Common.Extensions;
using Rw.Core.Common.Paging;
using WH.Common.Cache;
using WH.Common.Constant;
using WH.Common.Helper;
using WH.Common.Paging;
using WH.Common.UniOfWork;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace WH.WebApi.Controllers.Systems
{
    /// <summary>
    /// 用户接口
    /// </summary>
    [Authorize, Route("Users"), ApiController]
    public class UsersController : BaseController
    {
        //private readonly IUserRepository userRepository;
        //private readonly IUserLogonRepository userLogonRepository;
        //private readonly IRoleRepository roleRepository;
        //private readonly IDepartmentRepository departmentRepository;
        private readonly ICaching _caching;

        private readonly IUserService _userService;
        private readonly IUserLogonService _userLogonService;
        private readonly IRoleService _roleService;
        private readonly IUnitOfWork _unitOfWork;

        private readonly IOrganizationService _organizationService;
        private readonly IKeyValueService _keyValueService;


        /// <summary>
        /// 用户
        /// </summary>
        public UsersController(
                                 //IUserRepository userRepository,
                                 //                    IUserLogonRepository userLogonRepository,
                                 //                    IRoleRepository roleRepository,
                                 //                    IDepartmentRepository departmentRepository,
                                 IOrganizationService organizationService,
                                IUserService userService,
                                IUserLogonService userLogonService,
                                IRoleService roleService,
                                IKeyValueService keyValueService,
                                IUnitOfWork unitOfWork,
                                ICaching caching)
        {
            //this.userRepository = userRepository ?? throw new ArgumentNullException(nameof(userRepository));
            //this.userLogonRepository = userLogonRepository ?? throw new ArgumentNullException(nameof(userLogonRepository));
            //this.roleRepository = roleRepository ?? throw new ArgumentNullException(nameof(roleRepository));
            //this.departmentRepository = departmentRepository ?? throw new ArgumentNullException(nameof(departmentRepository));
            _caching = caching ?? throw new ArgumentNullException(nameof(caching));

            _userService = userService;
            _roleService = roleService;

            _userLogonService = userLogonService;

            _unitOfWork = unitOfWork;

            _organizationService = organizationService;

            _keyValueService = keyValueService;
        }

        /// <summary>
        /// 根据用户id获取用户
        /// </summary>
        /// <param name="id">用户Id</param>
        /// <returns></returns>
        [HttpGet("{id}")]
        public async Task<ResultResponse<UserOutputDto>> GetUserByIdAsync(string id)
        {
            var user = await _userService.FindByIdAsync(id);

            if (user == null)
            {
                return Error<UserOutputDto>("未查找到该用户，请重新操作");
            }

            var orgs = await _organizationService.FindAllAsync(x => x.IsEnable, true);

            var res = new UserOutputDto
            {
                Id = user.Id,
                Account = user.Account,
                Name = user.Name,
                Code = user.Code,
                SortCode = user.SortCode,
                IsEnable = user.IsEnable,
                OrganizationId = user.OrganizationId,
                OrganizationName = user.IsAdministrator ? "超级管理员机构" : user.Organization?.Name,
                FullOrganizationId = user.Organization?.Link,
                FullOrganizationName = user.IsAdministrator ? "超级管理员机构" : GetFullOrgName(orgs.ToList(), user.Organization?.Link),
                Remark = user.Remark,
                DepartmentId = user.DepartmentId,
                DepartmentName = user.Department?.Name,
                //DutyId = user.DutyId,
                RoleId = user.RoleId,
                RoleName = user.IsAdministrator ? "超级管理员" : user.Role?.Name,
                RoleDescription = user.Role?.Description,
                PhoneNumber = user.PhoneNumber,
                Email = user.Email,
                Sex = user.Sex,
                AvatarUrl = user.AvatarUrl,
                AccessType = (UserAccessTypeEnum?)user.AccessType,
                AccessTypeStr = ((UserAccessTypeEnum?)user.AccessType)?.ToDescription(),
                UserTypeCode = user.UserTypeCode,
                UserTypeCodeString = user.UserType?.Name,
                Birthday = user.Birthday,
            };

            return Success(res);
        }


        /// <summary>
        /// 根据Token获取用户
        /// </summary>
        /// <returns></returns>
        [HttpGet("Info")]
        public async Task<ResultResponse<UserOutputDto>> GetUserByTokenAsync()
        {
            var id = LoginDto.UserId;
            if (string.IsNullOrWhiteSpace(id))
            {
                return Error<UserOutputDto>("Token Is Expired.");
            }

            var user = await _userService.FindByIdAsync(id);

            if (user == null)
            {
                return Error<UserOutputDto>("未查找到该用户，请重新操作");
            }

            var orgs = await _organizationService.FindAllAsync(x => x.IsEnable, true);

            var res = new UserOutputDto
            {
                Id = user.Id,
                Account = user.Account,
                Name = user.Name,
                Code = user.Code,
                SortCode = user.SortCode,
                IsEnable = user.IsEnable,
                OrganizationId = user.OrganizationId,
                OrganizationName = user.IsAdministrator ? "超级管理员机构" : user.Organization?.Name,
                FullOrganizationId = user.Organization?.Link,
                FullOrganizationName = user.IsAdministrator ? "超级管理员机构" : GetFullOrgName(orgs.ToList(), user.Organization?.Link),
                Remark = user.Remark,
                DepartmentId = user.DepartmentId,
                DepartmentName = user.Department?.Name,
                //DutyId = user.DutyId,
                RoleId = user.RoleId,
                RoleName = user.IsAdministrator ? "超级管理员" : user.Role?.Name,
                RoleDescription = user.Role?.Description,
                PhoneNumber = user.PhoneNumber,
                Email = user.Email,
                Sex = user.Sex,
                AvatarUrl = user.AvatarUrl,
                AccessType = (UserAccessTypeEnum?)user.AccessType,
                AccessTypeStr = ((UserAccessTypeEnum?)user.AccessType)?.ToDescription(),
                UserTypeCode = user.UserTypeCode,
                UserTypeCodeString = user.UserType?.Name,
                Birthday = user.Birthday,
            };
            return Success(res);
        }

        /// <summary>
        /// 添加用户
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [HttpPost("")]
        public async Task<ResultResponse> PostAsync([FromBody] UserInputDto input)
        {
            if (input.OrganizationId == BusinessFunction.TopParentId)
            {
                return Error("不能向添加超级管理员机构添加用户");
            }

            var exist = await _userService.ExistsNoFilterAsync(x => x.Account == input.Account && x.Id != input.Id);
            if (exist)
            {
                return Error("请确保用户账号唯一，请重新操作");
            }

            if (!string.IsNullOrWhiteSpace(input.Code))
            {
                var existCode = await _userService.ExistsNoFilterAsync(x => x.Code == input.Code && x.Id != input.Id);
                if (existCode)
                {
                    return Error("请确保用户编号唯一，请重新操作");
                }
            }

            if (!string.IsNullOrWhiteSpace(input.CardTypeNo))
            {
                var existCardTypeNo = await _userService.ExistsNoFilterAsync(x => x.CardTypeNo == input.CardTypeNo && x.Id != input.Id);
                if (existCardTypeNo)
                {
                    return Error("请确保用户证件号码唯一，请重新操作");
                }
            }

            var roleE = await _roleService.ExistsAsync(x => x.Id == input.RoleId && x.OrganizationId == input.OrganizationId);

            if (!roleE)
            {
                return Error("当前机构不包含此角色，请重新操作");
            }

            var user = new UserEntity
            {
                Id = Snowflake.GetNewId(),
                Account = input.Account,
                Name = input.Name,
                SortCode = input.SortCode,
                IsEnable = input.IsEnable,
                Sex = input.Sex,
                Remark = input.Remark,
                OrganizationId = input.OrganizationId,
                DepartmentId = input.DepartmentId,
                RoleId = input.RoleId,
                Email = input.Email,
                PhoneNumber = input.PhoneNumber ?? "",
                AccessType = (int?)input.AccessType,
                UserTypeCode = input.UserTypeCode,
                Birthday = input.Birthday,
                WeiXin = input.WeiXin,
                AvatarUrl = input.AvatarUrl,
                CardTypeCode = input.CardTypeCode,
                CardTypeNo = input.CardTypeNo,
                Code = input.Code
            };

            if (string.IsNullOrWhiteSpace(input.Password))
            {
                input.Password = SecurityHelper.FrontendAesEncrypt(input.Account);
            }

            if (!string.IsNullOrWhiteSpace(input.Password))
            {
                string password = SecurityHelper.FrontendAesDecrypt(input.Password);

                var secretKey = Md5.MD5Hash(Utils.CreateNo()).ToLower();
                var passWord = Md5.MD5Hash(DESEncrypt.Encrypt(password.ToLower(), secretKey).ToLower()).ToLower();
                var logOnEntity = new UserLogonEntity
                {
                    Id = user.Id,
                    OrganizationId = user.OrganizationId,
                    Password = passWord,
                    SecretKey = secretKey,
                    UpdatedTime = DateTime.Now
                };

                await _userLogonService.CreateAsync(logOnEntity);
            }

            var res = await _userService.CreateAsync(user);

            return res > 0 ? Success() : Error();
        }

        /// <summary>
        /// 编辑用户
        /// </summary>
        /// <param name="id"></param>
        /// <param name="input"></param>
        /// <returns></returns>
        [HttpPut("{id}")]
        public async Task<ResultResponse> PutAsync(string id, [FromBody] UserInputDto input)
        {
            var exist = await _userService.ExistsNoFilterAsync(a => a.Id != id && a.Account == input.Account);
            if (exist)
            {
                return Error("请确保用户账号唯一，请重新操作");
            }

            if (!string.IsNullOrWhiteSpace(input.Code))
            {
                var existCode = await _userService.ExistsNoFilterAsync(x => x.Id != id && x.Code == input.Code);
                if (existCode)
                {
                    return Error("请确保用户编号唯一，请重新操作");
                }
            }

            if (!string.IsNullOrWhiteSpace(input.CardTypeNo))
            {
                var existCardTypeNo = await _userService.ExistsNoFilterAsync(x => x.Id != id && x.CardTypeNo == input.CardTypeNo);
                if (existCardTypeNo)
                {
                    return Error("请确保用户证件号码唯一，请重新操作");
                }
            }

            var user = await _userService.FindByIdAsync(id);
            if (user == null)
            {
                return Error("未查找到该用户，请重新操作");
            }

            if (user.IsAdministrator)
            {
                if (input.OrganizationId != BusinessFunction.TopParentId)
                {
                    return Error("超级管理员不能调整机构");
                }
                if (input.IsEnable == false)
                {
                    return Error("超级管理员不能禁用");
                }
            }

            var roleE = await _roleService.ExistsAsync(x => x.Id == input.RoleId && x.OrganizationId == input.OrganizationId);

            if (!roleE)
            {
                return Error("当前机构不包含此角色，请重新操作");
            }

            user.Account = input.Account;
            user.Name = input.Name;
            user.SortCode = input.SortCode;
            user.IsEnable = input.IsEnable;
            user.Sex = input.Sex;
            user.Remark = input.Remark;
            user.OrganizationId = input.OrganizationId;
            user.DepartmentId = input.DepartmentId;
            user.RoleId = input.RoleId;
            user.Email = input.Email;
            user.PhoneNumber = input.PhoneNumber ?? "";
            //user.AccessType = (int?)input.AccessType;
            user.UserTypeCode = input.UserTypeCode;
            user.Birthday = input.Birthday;
            user.WeiXin = input.WeiXin;
            user.AvatarUrl = input.AvatarUrl;
            user.CardTypeCode = input.CardTypeCode;
            user.CardTypeNo = input.CardTypeNo;
            user.Code = input.Code;

            var res = await _userService.UpdateAsync(user);


            if (!string.IsNullOrWhiteSpace(input.Password))
            {
                string password = SecurityHelper.FrontendAesDecrypt(input.Password);

                var secretKey = Md5.MD5Hash(Utils.CreateNo()).ToLower();
                var passWord = Md5.MD5Hash(DESEncrypt.Encrypt(password.ToLower(), secretKey).ToLower()).ToLower();
                var logOnEntity = await _userLogonService.FindByIdAsync(user.Id);
                var has = true;
                if (logOnEntity == null)
                {
                    has = false;
                    logOnEntity = new UserLogonEntity
                    {
                        Id = user.Id,
                    };
                }

                logOnEntity.OrganizationId = user.OrganizationId;
                logOnEntity.Password = passWord;
                logOnEntity.SecretKey = secretKey;

                if (has)
                {
                    await _userLogonService.UpdateAsync(logOnEntity);
                }
                else
                {
                    await _userLogonService.CreateAsync(logOnEntity);
                }
            }

            return res > 0 ? Success() : Error();
        }

        /// <summary>
        ///用户删除
        /// </summary>
        /// <param name="ids">主键集合</param>
        /// <returns></returns>
        [HttpDelete("")]
        public async Task<ResultResponse> DeleteAsync([FromBody] List<string> ids)
        {
            var users = await _userService.FindAllAsync(x => ids.Contains(x.Id));

            var dels = users.Where(x => x.IsAdministrator != true).Select(x => x.Id);

            try
            {
                await _unitOfWork.BeginTranAsync();

                await _userService.RemoveAsync(a => dels.Contains(a.Id));
                await _userLogonService.RemoveAsync(a => dels.Contains(a.Id));

                await _unitOfWork.CommitTranAsync();
            }
            catch (Exception)
            {
                await _unitOfWork.RollbackTranAsync();
                throw;
            }

            return Success();
        }

        /// <summary>
        /// 基础用户列表数据
        /// </summary>
        /// <param name="pager">分页</param>
        /// <param name="filter">查询实体参数请求</param>
        /// <returns></returns>
        [HttpGet("")]
        public async Task<ResultResponse<IPagedList<UserOutputByPageDto>>> GetUsersByPageAsync([FromQuery] PageParam pager, [FromQuery] UserFilterDto filter)
        {
            var filterData = new UserFilter();
            if (filter != null)
            {
                filterData.Keyword = filter.Keyword;
                filterData.Account = filter.Account;
                filterData.PhoneNumber = filter.PhoneNumber;
                filterData.Name = filter.Name;
                filterData.OrganizationId = filter.OrganizationId;
                filterData.IsEnable = filter.IsEnable;
                filterData.UserTypeCode = filter.UserTypeCode;
                filterData.RoleId = filter.RoleId;
                filterData.RoleTypeCode = filter.RoleTypeCode;
            }

            var orgs = await _organizationService.FindAllAsync(x => x.IsEnable, true);

            var pagedList = await _userService.GetUsersByPageAsync(pager, filterData);
            IPagedList<UserOutputByPageDto> data = new PagedList<UserOutputByPageDto>()
            {
                PageIndex = pagedList.PageIndex,
                PageSize = pagedList.PageSize,
                TotalCount = pagedList.TotalCount,
                Entities = pagedList.Entities.Select(x => new UserOutputByPageDto
                {
                    Id = x.Id,
                    Account = x.Account,
                    Name = x.Name,
                    Code = x.Code,
                    IsEnable = x.IsEnable,
                    OrganizationId = x.OrganizationId,
                    OrganizationName = x.IsAdministrator ? "超级管理员机构" : x.Organization?.Name,
                    FullOrganizationId = x.Organization?.Link,
                    FullOrganizationName = x.IsAdministrator ? "超级管理员机构" : GetFullOrgName(orgs.ToList(), x.Organization?.Link),
                    CreatedBy = x.CreatedBy,
                    CreatedTime = x.CreatedTime,
                    RoleId = x.RoleId,
                    RoleName = x.IsAdministrator ? "超级管理员" : x.Role?.Name,
                    RoleDescription = x.Role?.Description,
                    //DutyId = x.DutyId,
                    //DutyName = x.Duty?.Name,
                    DepartmentId = x.DepartmentId,
                    DepartmentName = x.Department?.Name,
                    PhoneNumber = x.PhoneNumber,
                    AccessType = (UserAccessTypeEnum?)x.AccessType,
                    AccessTypeStr = ((UserAccessTypeEnum?)x.AccessType)?.ToDescription(),
                    UserTypeCode = x.UserTypeCode,
                    UserTypeCodeString = x.UserType?.Name,
                    Birthday = x.Birthday,
                    WeiXin = x.WeiXin,
                }).ToList()
            };

            return Success(data);
        }


        /// <summary>
        /// 禁用用户
        /// </summary>
        /// <param name="keyValues"></param>
        /// <returns></returns>
        [HttpPut("Disabled")]
        public async Task<ResultResponse> DisabledAsync([FromBody] List<string> keyValues)
        {
            var users = await _userService.FindAllAsync(x => keyValues.Contains(x.Id) && x.IsAdministrator == false);

            foreach (var user in users)
            {
                if (user.IsAdministrator)
                {
                    continue;
                }
                user.IsEnable = false;
            }
            var row = await _userService.UpdateAsync(users);

            return row > 0 ? Success("账户禁用成功") : Error();

        }

        /// <summary>
        /// 启用用户
        /// </summary>
        /// <param name="keyValues"></param>
        /// <returns></returns>
        [HttpPut("Enabled")]
        public async Task<ResultResponse> EnabledAsync([FromBody] List<string> keyValues)
        {
            var users = await _userService.FindAllAsync(x => keyValues.Contains(x.Id));
            foreach (var user in users)
            {
                user.IsEnable = true;
            }

            var row = await _userService.UpdateAsync(users);

            return row > 0 ? Success("账户启用成功") : Error();

        }

        /// <summary>
        /// 重置密码
        /// </summary>
        /// <param name="id"></param>
        /// <param name="password"></param>
        /// <returns></returns>
        [HttpPut("Password/Reset/{id}")]
        public async Task<ResultResponse> ResetPasswordAsync(string id)
        {
            if (LoginDto.IsAdmin == false)
            {
                return Error("非管理员不能重置密码");
            }

            var user = await _userService.FindByIdAsync(id);
            if (user == null)
            {
                return Error("未找到该用户");
            }

            var password = SecurityHelper.FrontendAesEncrypt(user.Account);

            var res = await ChangePassword(new UserChangePasswordDto() { Id = id, NewPassword = password });

            return res.IsSucceed ? Success("密码已经重置为用户账号") : Error();
        }

        /// <summary>
        /// 修改密码
        /// </summary>
        /// <param name="passwordDto"></param>
        /// <returns></returns>
        [HttpPut("Password/Change")]
        public async Task<ResultResponse> ChangePasswordAsync([FromBody] UserChangePasswordDto passwordDto)
        {
            passwordDto.Id = LoginUserId;
            return await ChangePassword(passwordDto);
        }

        ///// <summary>
        ///// 忘记密码修改密码
        ///// </summary>
        ///// <param name="inputDto"></param>
        ///// <returns></returns>
        //[AllowAnonymous]
        //[HttpPut("Password/ChangeByForget")]
        //public async Task<ResultResponse> ChangePasswordByForgetAsync([FromBody] ForgetPasswordResetInputDto inputDto)
        //{
        //    var department = await departmentRepository.FirstOrDefaultAsync(x => x.DeptCode == inputDto.DeptCode);

        //    if (department is null)
        //    {
        //        return Error("科室不存在，请检查科室编号！");
        //    }

        //    var user = await userRepository.FirstOrDefaultAsync(x => x.Account == inputDto.UserAccount && x.DepartmentId == department.Id && x.Code == inputDto.UserCode);

        //    if (user is null)
        //    {
        //        return Error("用户不存在，请检查账号或工号是否正确！");
        //    }


        //    return await ChangePassword(user.Id, inputDto.Password ?? "");
        //}

        private async Task<ResultResponse> ChangePassword(UserChangePasswordDto passwordDto)
        {
            if (string.IsNullOrWhiteSpace(passwordDto.Id))
            {
                return Error("未找到该用户");
            }

            var user = await _userService.FindByIdAsync(passwordDto.Id);
            if (user == null)
            {
                return Error("未找到该用户");
            }

            //if (string.IsNullOrWhiteSpace(password))
            //{
            //    return Error("密码不可为空");
            //}


            if (LoginDto.IsAdmin == false)
            {
                if (string.IsNullOrWhiteSpace(passwordDto.OldPassword))
                {
                    return Error("原密码不能为空");
                }
            }
            var logon = await _userLogonService.FindByIdAsync(passwordDto.Id) ?? new UserLogonEntity { Id = user.Id, OrganizationId = user.OrganizationId };

            if (LoginDto.IsAdmin == false || LoginDto.UserId == passwordDto.Id)
            {
                var oldPassWord = Md5.MD5Hash(DESEncrypt.Encrypt(SecurityHelper.FrontendAesDecrypt(passwordDto.OldPassword), logon.SecretKey).ToLower()).ToLower();
                if (oldPassWord != logon.Password)
                {
                    return Error("原密码不正确，请重新输入");
                }
            }

            var newPassword = SecurityHelper.FrontendAesDecrypt(passwordDto.NewPassword);

            var secretKey = Md5.MD5Hash(Utils.CreateNo()).ToLower();
            var passWord = Md5.MD5Hash(DESEncrypt.Encrypt(newPassword.ToLower(), secretKey).ToLower()).ToLower();

            logon.Password = passWord;
            logon.SecretKey = secretKey;

            var key = $"{BusinessFunction.TrialTimes}:{logon.Id}";

            _caching.Remove(key);

            var res = await _userLogonService.SaveAsync(logon);

            return res > 0 ? Success("密码修改成功") : Error();
        }

        private string? GetFullOrgName(IList<OrganizationEntity> orgs, string? ids)
        {
            if (ids is null)
            {
                return default;
            }

            var idArr = ids.Split('|');

            var fullnames = new List<string>();

            if (idArr.Length > 0)
            {

                foreach (var id in idArr)
                {
                    var org = orgs.FirstOrDefault(x => x.Id == id);

                    if (org is not null)
                    {
                        fullnames.Add(org.Name);
                    }
                }
            }

            return string.Join(@"/", fullnames);
        }

    }
}